/**
 * @file       main.c
 * @author     mz8023yt
 * @email      mz8023yt@163.com
 * @version    V1.0
 * @date       2022-03-13
 * @brief      st7789 lcd test
 */

#include "driver/gpio.h"
#include "driver/spi_master.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "st7789.h"
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#include "colorbar.h"

#include "esp_lcd_panel_interface.h"
#include "esp_lcd_panel_io.h"
#include "esp_lcd_panel_io_interface.h"
#include "esp_lcd_panel_ops.h"
#include "esp_lcd_panel_vendor.h"

#define ST7789_CS_PIN  18
#define ST7789_DC_PIN  17
#define ST7789_WR_PIN  16
#define ST7789_RD_PIN  15
#define ST7789_RST_PIN 14
#define ST7789_BL_PIN  13
#define ST7789_D0_PIN  0
#define ST7789_D1_PIN  1
#define ST7789_D2_PIN  2
#define ST7789_D3_PIN  3
#define ST7789_D4_PIN  4
#define ST7789_D5_PIN  5
#define ST7789_D6_PIN  6
#define ST7789_D7_PIN  7

esp_lcd_panel_io_t* io_handle = NULL;

void esp32_rst_pin(int val)
{
	gpio_set_level(ST7789_RST_PIN, val);
}

void esp32_bl_pin(int val)
{
	gpio_set_level(ST7789_BL_PIN, val);
}

void esp32_msleep(int ms)
{
	usleep(1000 * ms);
}

static void esp32_i80_reg_write(uint8_t cmd, uint8_t* param, int len)
{
	gpio_set_level(ST7789_RD_PIN, 1);
	io_handle->tx_param(io_handle, cmd, param, len);
}

static void esp32_i80_color_write(uint8_t cmd, uint8_t* dat, int len)
{
	gpio_set_level(ST7789_RD_PIN, 1);
	io_handle->tx_color(io_handle, cmd, dat, len);
}

void board_init()
{
	esp_lcd_i80_bus_config_t bus_config;
	esp_lcd_i80_bus_handle_t i80_bus = NULL;
	esp_lcd_panel_io_i80_config_t io_config;

	/* gpio */
	gpio_reset_pin(ST7789_RD_PIN);
	gpio_set_direction(ST7789_RD_PIN, GPIO_MODE_OUTPUT);

	gpio_reset_pin(ST7789_RST_PIN);
	gpio_set_direction(ST7789_RST_PIN, GPIO_MODE_OUTPUT);

	gpio_reset_pin(ST7789_BL_PIN);
	gpio_set_direction(ST7789_BL_PIN, GPIO_MODE_OUTPUT);

	/* intel 8080 lcd interface */
	bus_config.clk_src = LCD_CLK_SRC_DEFAULT;
	bus_config.dc_gpio_num = ST7789_DC_PIN;
	bus_config.wr_gpio_num = ST7789_WR_PIN;
	bus_config.data_gpio_nums[0] = ST7789_D0_PIN;
	bus_config.data_gpio_nums[1] = ST7789_D1_PIN;
	bus_config.data_gpio_nums[2] = ST7789_D2_PIN;
	bus_config.data_gpio_nums[3] = ST7789_D3_PIN;
	bus_config.data_gpio_nums[4] = ST7789_D4_PIN;
	bus_config.data_gpio_nums[5] = ST7789_D5_PIN;
	bus_config.data_gpio_nums[6] = ST7789_D6_PIN;
	bus_config.data_gpio_nums[7] = ST7789_D7_PIN;
	bus_config.bus_width = 8;
	bus_config.max_transfer_bytes = 240 * 240 * sizeof(uint16_t);
	bus_config.psram_trans_align = 64;
	bus_config.sram_trans_align = 4;
	esp_lcd_new_i80_bus(&bus_config, &i80_bus);

	io_config.cs_gpio_num = ST7789_CS_PIN;
	io_config.pclk_hz = 10000000;
	io_config.trans_queue_depth = 10;
	io_config.dc_levels.dc_idle_level = 0;
	io_config.dc_levels.dc_cmd_level = 0;
	io_config.dc_levels.dc_dummy_level = 0;
	io_config.dc_levels.dc_data_level = 1;
	io_config.flags.swap_color_bytes = 0;
	io_config.on_color_trans_done = NULL;
	io_config.user_ctx = NULL;
	io_config.lcd_cmd_bits = 8;
	io_config.lcd_param_bits = 8;
	esp_lcd_new_panel_io_i80(i80_bus, &io_config, &io_handle);
}

void app_main(void)
{
	struct st7789 lcd;
	uint8_t* buf = NULL;

	board_init();

	/* set lcd param */
	lcd.cfg.fix.width = 240;
	lcd.cfg.fix.height = 240;
	lcd.cfg.fix.xshift = 0;
	lcd.cfg.fix.yshift = 0;
	lcd.cfg.var.orien = 0;

	/* register the operation */
	lcd.ops.reset = esp32_rst_pin;
	lcd.ops.backlight = esp32_bl_pin;
	lcd.ops.msleep = esp32_msleep;
	lcd.ops.i80_reg_write = esp32_i80_reg_write;
	lcd.ops.i80_color_write = esp32_i80_color_write;

	/* display panel init */
	st7789_init(&lcd);

	/* display colorbar */
	buf = malloc(lcd.cfg.fix.width * lcd.cfg.fix.height * 2);
	colorbar_generate(buf, lcd.cfg.fix.width, lcd.cfg.fix.height);
	// memset(buf, 0xff, lcd.cfg.fix.width * lcd.cfg.fix.height * 2);
	st7789_rect_fill(&lcd, 0, 0, lcd.cfg.fix.width - 1, lcd.cfg.fix.height - 1, buf);

	while (1) {
		vTaskDelay(1000 / portTICK_PERIOD_MS);
	}

	free(buf);
}
